/**
 * See
 * https://developer.mozilla.org/index.php?title=En/Code_snippets/Drag_%26_Drop
 * https://developer.mozilla.org/en/XUL_Tutorial/Custom_Tree_Views
 */
function draggingUrl() {
     var dragService = Components.classes["@mozilla.org/widget/dragservice;1"]
                        .getService(Components.interfaces.nsIDragService);
     var dragSession = dragService.getCurrentSession();

     var supported = dragSession.isDataFlavorSupported("text/x-moz-url");
     // Tabs show up as application/x-moz-tabbrowser-tab and
	 // text/x-moz-text-internal
     if (!supported)
         var supported = dragSession.isDataFlavorSupported("text/x-moz-text-internal");
    	 // alert(inspectList(dragSession.dataTransfer.types));
     return supported;
}

function ondrop(dragEvent) {
	if (dragEvent.target.id != "sideBarList")
		return;	
	
	// Destination
    var tree = document.getElementById(BINDER_TREE_ID);
    var row = tree.treeBoxObject.getRowAt(dragEvent.clientX, dragEvent.clientY);
    
    if (row < 0)
    	return;
   	var binder = treeView.getBinder(row);
   	
   	// Source
    var dragService = Components.classes["@mozilla.org/widget/dragservice;1"]
                                         .getService(Components.interfaces.nsIDragService);
    var dragSession = dragService.getCurrentSession();
    // Setup a transfer item to retrieve the file data
    var trans = Components.classes["@mozilla.org/widget/transferable;1"]
                    .createInstance(Components.interfaces.nsITransferable);
    trans.addDataFlavor("text/x-moz-url");
    trans.addDataFlavor("text/x-moz-text-internal"); // for tabs
    
    for ( var i = 0; i < dragSession.numDropItems; i++) {
        var uri = null;

        dragSession.getData(trans, i);
        var flavor = {}, data = {}, length = {};
        trans.getAnyTransferData(flavor, data, length);
        if (data) 
            try {
                var str = data.value.QueryInterface(Components.interfaces.nsISupportsString);
                if (str) {
                	var parts = str.data.split("\n");
                	var v = {"url": parts[0]};
                	if (parts.length > 1)
                		v.title = parts[1];
               		binder.links.push(v);
                }
            } catch (ex) {}
    }

    withLogin(function a() {sendBinder(binder, loadSidebarList)}, false, window);
}

function reloadBinderSidebar(window) {
	var tree = document.getElementById(BINDER_TREE_ID);
	treeView.isLoading = true;	
	tree.view = treeView;
	withLogin(loadSidebarList, cancelSidebarList, window);
}

function loadSidebarList() {
	getBinders(function a(list) {
		var tree = document.getElementById(BINDER_TREE_ID);
		tree.dataStore = list;
		treeView.isLoading = false;
		tree.view = treeView;
	});
}

function cancelSidebarList() {
	var tree = document.getElementById(BINDER_TREE_ID);
	tree.dataStore = null;
	treeView.isLoading = false;
	tree.view = treeView;
}

/** On DBL click */
function treeClicked(event) {
    var tree = document.getElementById(BINDER_TREE_ID);
    var row = tree.treeBoxObject.getRowAt(event.clientX, event.clientY);
    if (row >= 0) 
    	doOpen(row);
}

/** Open all tabs in currently selected binder */
function openWholeBinder(ignoreOpened) {
	if (treeView.selection != null) 
		doOpen(treeView.selection.currentIndex, ignoreOpened);
}

function closeCurrentBinder() {
	if (treeView.selection == null) return;
	var binder = treeView.getBinder(treeView.selection.currentIndex);
	if (binder != null)
		closeBinder(binder);		
}

function deleteCurrentBinder() {
	if (treeView.selection == null) return;
	var binder = treeView.getBinder(treeView.selection.currentIndex);
	if (binder == null) return;
	if (binder.startRow == treeView.selection.currentIndex) {
		if (!confirm("Delete binder " + binder.title + "?")) return;
		withLogin(function a() {deleteBinder(binder.id, loadSidebarList)}, false, window);
	} else {
		var idx = treeView.selection.currentIndex - binder.startRow - 1;
		var link = binder.links[idx];
		var msg = link.url;
		if (link.title) msg = link.title;
		if (!confirm("Delete link " + msg + "?")) return;
		binder.links.splice(idx, 1);
		withLogin(function a() {sendBinder(binder, loadSidebarList)}, false, window);
	}
}

function doOpen(row, ignoreOpened) {
   	var binder = treeView.getBinder(row);
   	if (binder == null) return;
   	if (binder.startRow == row) {
   		var tabs = getTabsAsList();
   		for (var i=0; i<binder.links.length; i++) 
   			if (!ignoreOpened || findTab(tabs, binder.links[i].url) < 0)
   				openPage(binder.links[i].url);
   	} else {
   		openPage(binder.links[row - binder.startRow - 1].url);
   	}	
}

function createAndReload() {
	openCreateBinderBox(loadSidebarList);
}

/** Tree model */
var treeView = {
	treeBox: null,
	selection: null,
	isLoading: false,

	getData : function() {
	    try {return document.getElementById(BINDER_TREE_ID).dataStore;}
	    catch (e) {return null}},
	get rowCount() { 
	    if (this.isLoading) return 1;
	    var data = this.getData();
		if (data == null) return 1;
		var count = 0;
		for (var i=0; i<data.length; i++) {
			data[i].startRow = count;
			if (data[i].open) count = count + 1 + data[i].links.length;
			else count++;
		}
		return count; 
	},
	/** Find binder that includes the given index */
	getBinder: function(idx, data) {
		if (!data) data = this.getData();
		if (data == null) return null;
		for (var i=1; i<data.length; i++)
			if (data[i].startRow > idx) return data[i-1];
		return data[data.length-1];
	},
	setTree: function(treeBox)         { this.treeBox = treeBox; },
	getCellText: function(idx, column) { 
		if (this.isLoading) return "Loading...";
		var binder = this.getBinder(idx);
		if (binder == null) return "No data";
		idx = idx - binder.startRow;
		if (idx == 0) return binder.title;
		if (!binder.links[idx-1].title) return binder.links[idx-1].url;
		return binder.links[idx-1].title
	},
	isContainer: function(idx)         { 
		var binder = this.getBinder(idx);
		if (binder == null) return false;
		return (binder.startRow == idx); },
	isContainerOpen: function(idx)     { return this.getBinder(idx).open; },
	isContainerEmpty: function(idx)    { return false; },
	isSeparator: function(idx)         { return false; },
	isSorted: function()               { return false; },
	isEditable: function(idx, column)  { return false; },

	getParentIndex: function(idx) {
		var binder = this.getBinder(idx);
		if (idx == binder.startRow) return -1;
		return binder.startRow;
	},
	getLevel: function(idx) {
		if (this.isContainer(idx)) return 0;
		return 1;
	},
	hasNextSibling: function(idx, after) {
		var data = this.getData();
		var binder = this.getBinder(idx, data);
		// the last binder?
		if (binder.startRow == idx) return (data[data.length-1].startRow != idx);
		return idx - binder.startRow < binder.links.length-1;
	},
	toggleOpenState: function(idx) {
		var data = this.getData();
		var bdx = data.length-1;
		for (var i=1; i<data.length; i++)
			if (data[i].startRow > idx) { bdx = i-1; break; }		
		if (idx != data[bdx].startRow) return; // not a container
		  	
	  	// For change reporting: point and size
		var point = data[bdx].startRow + 1;
		var change = 0;
		var next = point; // will change this one as we go over binders
		if (data[bdx].open) {
			data[bdx].open = false;
			change = -data[bdx].links.length;
		} else {
			data[bdx].open = true;
			next = next + data[bdx].links.length;
			change = data[bdx].links.length;
		}
			  
		// Renumber the rest of binders. Same as rowCount()
		bdx++;
		while (bdx < data.length) {
			data[bdx].startRow = next;
			if (data[bdx].open) next = next + data[bdx].links.length;
			next++; bdx++;
		}
			  
	    this.treeBox.rowCountChanged(point, change);
	    this.treeBox.invalidateRow(idx);
	},

	getImageSrc: function(idx, column) {},
	getProgressMode : function(idx,column) {},
	getCellValue: function(idx, column) {},
	cycleHeader: function(col, elem) {},
	selectionChanged: function() {},
	cycleCell: function(idx, column) {},
	performAction: function(action) {},
	performActionOnCell: function(action, index, column) {},
	getRowProperties: function(idx, column, prop) {},
	getCellProperties: function(idx, column, prop) {},
	getColumnProperties: function(column, element, prop) {},
	
	// void drop(in long row, in long orientation, in nsIDOMDataTransfer
	// transfer);
	canDrop : function (index, orientation, dataTransfer) {return draggingUrl();}
}; // of treeView
